home *** CD-ROM | disk | FTP | other *** search
/ PsL Monthly 1993 December / PSL Monthly Shareware CD-ROM (December 1993).iso / prgmming / win / pascal / dynst.exe / DYNST1.PAS < prev    next >
Pascal/Delphi Source File  |  1991-10-18  |  10KB  |  344 lines

  1. UNIT DYNSTR1;
  2. { ================================================================
  3.   DYNSTR1.PAS
  4.  
  5.   Compiler:        Turbo Pascal for Windows v. 1
  6.   Date:            10/18/91
  7.   By:              Tom Campbell
  8.   What it is:      Dynamic string array unit
  9.   What it's for:   Allocating arrays of strings on the heap, and
  10.                    handling all memory management transparently.
  11.  
  12.                    An interactive demo program shows how to use
  13.                    this unit. It appears after the last END of
  14.                    the unit.
  15.  
  16.                    Copyright (C) 1991 by Tom Campbell.
  17.  
  18.                    You may use this however you wish as long as
  19.                    you retain the copyright notice in the source
  20.                    code.
  21.  
  22.   ================================================================ }
  23.  
  24. { Publicly visible routines & data types. }
  25. INTERFACE
  26. CONST
  27.   { Biggest dynamic variable that can be allocated. Actually, it's not
  28.     quite the biggest.  I'm leaving slop memory just to be sure. }
  29.   MaxArraySize = 64000;
  30.  
  31.   { Figure out how big the biggest possible array could be. This amount
  32.     won't necessarily be allocated, but it's used to fool Pascal into
  33.     allowing us to address a dynamically allocated array of any size
  34.     from 1 to MaxStrArraySize. }
  35.   MaxStrArraySize = MaxArraySize DIV SizeOf(STRING);
  36.  
  37. TYPE
  38.  
  39.   { With range checking disabled, this can be used to create a
  40.     dynamically sized array of pointers to strings. }
  41.   PStrArray = ^TStrArray;
  42.   TStrArray = ARRAY[0..MaxStrArraySize - 1] OF STRING;
  43.  
  44.  
  45.   { This is a dynamically allocated array of pointers to strings.
  46.     LABuffer is short for "look ahead buffer". }
  47.   PTLABuffer = ^TLABuffer;
  48.   TLABuffer = OBJECT
  49.     { Error code. FALSE if everything's okay, TRUE if error. }
  50.     BufError : BOOLEAN;
  51.     { Size of array. }
  52.     BufSize : WORD;
  53.     { Current position in array.}
  54.     BufIndex : WORD;
  55.     { Address of first element of dynamically allocated array. }
  56.     BufStart : PStrArray;
  57.     { Deallocate dynamically allocated members of this
  58.       structure. }
  59.     DESTRUCTOR Done;
  60.     { Allocate an array. }
  61.     { Return error code: Simply TRUE there's an error, or FALSE
  62.       if not. }
  63.     FUNCTION Error : BOOLEAN;
  64.     CONSTRUCTOR Init(NumElements : WORD);
  65.     { Read string at array position Index and return it. }
  66.     FUNCTION ReadElement(VAR Index : WORD) : STRING;
  67.     { Returns # of elements in the dynamically allocated array. }
  68.     FUNCTION NumOfElements : WORD;
  69.     { Write a string to position Index. }
  70.     PROCEDURE WriteElement(VAR Index : WORD; Element : STRING);
  71.   END;
  72.  
  73.  
  74. { Routines in this unit. }
  75. IMPLEMENTATION
  76.  
  77.  
  78. DESTRUCTOR TLABuffer.Done;
  79. {==================================================================
  80.  What it does:
  81.    Returns dynamically allocated fields of this object.
  82.  
  83.  Example:
  84.    Dispose(Buf, Done);
  85.  
  86.  ==================================================================}
  87. BEGIN
  88.   { Return the dynamically allocated string array. }
  89.   FreeMem(BufStart, BufSize * SizeOf(STRING));
  90. END; { PROCEDURE DESTRUCTOR TLABuffer.Done }
  91.  
  92. FUNCTION TLABuffer.Error: BOOLEAN;
  93. {==================================================================
  94.  What it does:
  95.    Returns TRUE if an error has occurred, or FALSE if none has
  96.    occurred.
  97.  
  98.  Returns:
  99.  - TRUE if an error occurred.
  100.  - FALSE if not.
  101.  
  102.  Example:
  103.    IF Buf^.Error THEN
  104.     BEGIN
  105.       WriteLn('Unable to allocate a PLABuffer object. Quitting.');
  106.       Halt(1);
  107.     END;
  108.  ==================================================================}
  109. BEGIN
  110.   { This isn't a very challenging routine...}
  111.   Error := BufError;
  112. END; { FUNCTION TLABuffer.Error }
  113.  
  114. CONSTRUCTOR TLABuffer.Init(NumElements : WORD);
  115. {==================================================================
  116.  What it does:
  117.    Allocates an array of BufSize STRING elements. If there isn't
  118.    enough memory, sets BufError to a nonzero value. If there is,
  119.    sets BufError to FALSE.
  120.  
  121.    Initializes all strings to ''.
  122.  
  123.  Parameters:
  124.  - NumElements : The # of elements to be allocated for the string
  125.    array.
  126.  
  127.  Example:
  128.    New(Buf, Init(10));
  129.  ==================================================================}
  130. VAR
  131.   { Loop counter/array index. }
  132.   EachString : WORD;
  133.  
  134. BEGIN
  135.   { Assume an error (0 means none). }
  136.   BufError := TRUE;
  137.  
  138.   { Make sure it's not too big. }
  139.   IF NumElements < MaxStrArraySize THEN
  140.     BufSize := NumElements
  141.   ELSE
  142.     BEGIN
  143.       BufSize := 0;
  144.       Exit;
  145.     END;
  146.  
  147.   IF MaxAvail < (BufSize * SizeOf(STRING)) THEN
  148.     Exit;
  149.  
  150.   { If there is enough memory, allocate BufSize elements' worth
  151.     and point BufStart at that location. }
  152.   GetMem(BufStart, BufSize * SizeOf(STRING));
  153.  
  154.   { Set flag to "no error" if there's enough memory. }
  155.   BufError := FALSE;
  156.  
  157.   { Index starts at 0th element. }
  158.   BufIndex := 0;
  159.  
  160.   { Initialize all strings to null values. }
  161.   FOR EachString := 0 TO PRED(BufSize) DO
  162.     BufStart^[EachString] := #0;
  163.  
  164. END; { CONSTRUCTOR TLABuffer.Init }
  165.  
  166. FUNCTION TLABuffer.NumOfElements : WORD;
  167. {==================================================================
  168.  What it does:
  169.    Returns the # of elements in the array. This is of course the
  170.    same amount it was initialized with, assuming the initialization
  171.    was successful.
  172.  
  173.  Returns:
  174.  - # of elements in the array (0 if none could be allocated).
  175.  
  176.  Example:
  177.   WriteLn('# of elements in array:  ', Buf^.NumOfElements);
  178.  
  179.  ==================================================================}
  180. BEGIN
  181.   NumOfElements := BufSize;
  182. END; { FUNCTION TLABuffer.NumOfElements }
  183.  
  184. FUNCTION TLABuffer.ReadElement(VAR Index : WORD) : STRING;
  185. {==================================================================
  186.  What it does:
  187.    Retrieves a string at array index Index, writing it to
  188.    the return value. If there's an error--that is, the index is
  189.    past the end of the buffer--returns an empty string and sets
  190.    BufError to TRUE.
  191.  
  192.    If this were a real string array, this would be the equivalent
  193.    of
  194.      StrVariable = Buffer[Index];
  195.  
  196.  
  197.  Parameters:
  198.  - Index : Array element to read.
  199.  
  200.  Returns:
  201.  - The string at array position Index on success.
  202.  - A null string on failure.
  203.  
  204.  Example:
  205.   FOR i := 0 TO PRED(Buf^.BufSize) DO
  206.     BEGIN
  207.       WriteLn(Buf^.ReadElement(i));
  208.     END;
  209. ==================================================================}
  210. BEGIN
  211.   { See if the requested string is out of bounds. }
  212.   IF Index >= BufSize THEN
  213.     BEGIN
  214.       { Flag this as an error condition. }
  215.       BufError := TRUE;
  216.       { Return a known value. }
  217.       ReadElement := '';
  218.       { Exit this routine. }
  219.       Exit;
  220.     END;
  221.  
  222.   { Wasn't out of bounds. Return the string at this position. }
  223.   ReadElement := BufStart^[Index];
  224. END; { FUNCTION TLABuffer.ReadElement }
  225.  
  226. PROCEDURE TLABuffer.WriteElement(VAR Index : WORD; Element : STRING);
  227. {==================================================================
  228.  What it does:
  229.    Writes Element to array position Index. If Index is out of
  230.    bounds, does nothing and sets BufError to TRUE.
  231.  
  232.    If this were a real string array, this would be the equivalent
  233.    of
  234.      Buffer[Index] := Element;
  235.  
  236.  Parameters:
  237.  - Index : Array position to write string to.
  238.  - Element : String to write into array.
  239.  
  240.  Example:
  241.    Write('Please enter string #', i, ': ');
  242.    ReadLn(s);
  243.    Buf^.WriteElement(i, s);
  244.  
  245.  ==================================================================}
  246. BEGIN
  247.   { See if the requested string is out of bounds. }
  248.   IF Index >= BufSize THEN
  249.     BEGIN
  250.       { Flag this as an error condition. }
  251.       BufError := TRUE;
  252.       { Exit this routine. }
  253.       Exit;
  254.     END;
  255.  
  256.   { Everything's okay. Write the string in. }
  257.   BufStart^[Index] := Element;
  258.  
  259. END; { PROCEDURE TLABuffer.WriteElement }
  260.  
  261. END.
  262.  
  263. End of unit. Any comments can go here.
  264.  
  265. { ================================================================
  266.                      DEMO PROGRAM
  267.  
  268.   Asks for a small array (simply to keep the demo reasonably
  269.   short), then has user enter strings into it interactively.
  270.  
  271.   Displays them, th